﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchUtils.Utils;
using YJKArchUtils.Utils.Generics;

namespace YJKRevitRampModule.RampDataManager
{
	public class RampAnalyser
	{
		public RampAnalyser(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
		}

		public bool SerializeCurves(List<Curve> curves, ref List<Curve> serializedCurves, ref string message)
		{
			if (curves.Count == 0)
			{
				message = "曲线数量为0";
				return false;
			}
			Dictionary<XYZ, List<Curve>> dictionary = new Dictionary<XYZ, List<Curve>>(new XYZEqualityComparer());
			foreach (Curve curve in curves)
			{
				XYZ hyendPoint = curve.GetEndPoint(0);
				XYZ hyendPoint2 = curve.GetEndPoint(1);
				if (!dictionary.ContainsKey(hyendPoint))
				{
					dictionary.Add(hyendPoint, new List<Curve>
					{
						curve
					});
				}
				else
				{
					dictionary[hyendPoint].Add(curve);
				}
				if (!dictionary.ContainsKey(hyendPoint2))
				{
					dictionary.Add(hyendPoint2, new List<Curve>
					{
						curve
					});
				}
				else
				{
					dictionary[hyendPoint2].Add(curve);
				}
			}
			XYZ xyz = null;
			foreach (KeyValuePair<XYZ, List<Curve>> keyValuePair in dictionary)
			{
				XYZ key = keyValuePair.Key;
				List<Curve> value = keyValuePair.Value;
				if (value.Count > 2)
				{
					message = "所选参照线重叠或者存在分支";
					return false;
				}
				if (value.Count == 1 && xyz == null)
				{
					xyz = key;
				}
			}
			if (xyz == null)
			{
				message = "所选参照线不能为环";
				return false;
			}
			XYZ xyz2 = xyz;
			XYZ xyz3 = null;
			while (dictionary.ContainsKey(xyz2))
			{
				List<Curve> nodeValue = dictionary[xyz2];
				Curve curve2 = null;
				XYZ nextPoint = this.GetNextPoint(xyz2, nodeValue, xyz3, ref curve2);
				if (null != curve2)
				{
					Curve item = this.SerializeCurve(curve2, xyz3);
					serializedCurves.Add(item);
				}
				if (nextPoint == null)
				{
					break;
				}
				xyz3 = xyz2;
				xyz2 = nextPoint;
			}
			if (serializedCurves.Count != dictionary.Count - 1)
			{
				serializedCurves.Clear();
				message = "所选参照线不连续";
				return false;
			}
			return true;
		}

		public void GetAllSegmentData(Autodesk.Revit.DB.Document doc, List<SegmentData> lstStandardSegData, Dictionary<Level, List<SegmentData>> lstAllSegmentData)
		{
			List<Floor> list = (from f in new FilteredElementCollector(doc).OfClass(typeof(Floor))
			select f as Floor).ToList<Floor>();
			List<Floor> list2 = new List<Floor>();
			foreach (Floor floor in list)
			{
				List<double> widthList = this.GetWidthList(floor);
				if (widthList != null && widthList.Count > 0)
				{
					list2.Add(floor);
				}
			}
			List<Level> list3 = (from l in new FilteredElementCollector(doc).OfClass(typeof(Level))
			select l as Level).ToList<Level>();
			for (int i = 0; i < list3.Count - 1; i++)
			{
				for (int j = i + 1; j < list3.Count; j++)
				{
					if (list3[i].Elevation > list3[j].Elevation)
					{
						Level value = list3[i];
						list3[i] = list3[j];
						list3[j] = value;
					}
				}
			}
			foreach (Level level in list3)
			{
				List<Floor> list4 = new List<Floor>();
				foreach (Floor floor2 in list2)
				{
					if (floor2.LevelId == level.Id)
					{
						list4.Add(floor2);
					}
				}
				List<SegmentData> levelSegmentData = this.GetLevelSegmentData(doc, list4, lstStandardSegData);
				if (levelSegmentData != null && levelSegmentData.Count > 0)
				{
					lstAllSegmentData.Add(level, levelSegmentData);
				}
			}
		}

		public bool AnalyserRamp(Floor floor1, Floor floor2, ref List<SegmentData> segmentDataList, ref string message)
		{
			List<double> widthList = this.GetWidthList(floor1);
			List<double> widthList2 = this.GetWidthList(floor2);
			if (widthList2.Count < 1 || widthList.Count < 1)
			{
				return false;
			}
			List<Curve> curves = new List<Curve>();
			List<KeyValuePair<XYZ, double>> elevationMap = new List<KeyValuePair<XYZ, double>>();
			if (!this.AnalyserRamp(floor1, floor2, ref curves, ref elevationMap))
			{
				return false;
			}
			List<Curve> serializeCurves = new List<Curve>();
			if (!this.SerializeCurves(curves, ref serializeCurves, ref message))
			{
				return false;
			}
			segmentDataList = this.GetSegmentDataByPairFloor(serializeCurves, elevationMap, widthList, widthList2);
			if (segmentDataList.Count > 1)
			{
				double startElevation = segmentDataList[0].StartElevation;
				if (Geometry.LessThan(segmentDataList[segmentDataList.Count - 1].EndElevation, startElevation))
				{
					this.ReverseSegmentDatas(ref segmentDataList);
				}
			}
			List<double> vertArcRadius = this.GetVertArcRadius(floor1);
			this.SetSegmentVertRadius(segmentDataList, vertArcRadius);
			return true;
		}

		private List<SegmentData> GetLevelSegmentData(Autodesk.Revit.DB.Document doc, List<Floor> lstLevelFloor, List<SegmentData> lstStandardSegData)
		{
			string text = "";
			for (int i = 0; i < lstLevelFloor.Count - 1; i++)
			{
				Floor floor = lstLevelFloor[i];
				int j = i + 1;
				while (j < lstLevelFloor.Count)
				{
					Floor floor2 = lstLevelFloor[j];
					List<SegmentData> list = new List<SegmentData>();
					if (this.AnalyserRamp(floor, floor2, ref list, ref text))
					{
						if (this.EquipSegmentData(doc, list, lstStandardSegData))
						{
							return list;
						}
						break;
					}
					else
					{
						j++;
					}
				}
			}
			return null;
		}

		private bool EquipSegmentData(Autodesk.Revit.DB.Document doc, List<SegmentData> lstSegData1, List<SegmentData> lstSegData2)
		{
			if (lstSegData1 == null || lstSegData2 == null)
			{
				return true;
			}
			if (lstSegData1.Count != lstSegData2.Count)
			{
				return false;
			}
			for (int i = 0; i < lstSegData1.Count; i++)
			{
				Curve curve = lstSegData1[i].GetCurve(doc.Application);
				Curve curve2 = lstSegData2[i].GetCurve(doc.Application);
				if (curve.GetType() != curve2.GetType())
				{
					return false;
				}
				if (!Geometry.IsEqual(curve.GetEndPoint(0), curve2.GetEndPoint(0)))
				{
					return false;
				}
				if (!Geometry.IsEqual(curve.GetEndPoint(1), curve2.GetEndPoint(1)))
				{
					return false;
				}
			}
			return true;
		}

		private List<double> GetWidthList(Floor floor)
		{
			List<double> result = new List<double>();
			ExtensibleStorageManager.ReadRampExtensibleStorage(floor, ref result);
			return result;
		}

		private List<double> GetVertArcRadius(Floor floor)
		{
			List<double> result = new List<double>();
			ExtensibleStorageManager.ReadRampVertRadius(floor, ref result);
			return result;
		}

		private void ReverseSegmentDatas(ref List<SegmentData> segmentDataList)
		{
			foreach (SegmentData segmentData in segmentDataList)
			{
				XYZ startPoint = segmentData.StartPoint;
				segmentData.StartPoint = segmentData.EndPoint;
				segmentData.EndPoint = startPoint;
				segmentData.Bulge = -segmentData.Bulge;
				double endElevation = segmentData.EndElevation;
				segmentData.EndElevation = segmentData.StartElevation;
				segmentData.StartElevation = endElevation;
				double leftWidth = segmentData.LeftWidth;
				segmentData.LeftWidth = segmentData.RightWidth;
				segmentData.RightWidth = leftWidth;
			}
			segmentDataList.Reverse();
		}

		private bool AnalyserRamp(Floor floor1, Floor floor2, ref List<Curve> centerLineList, ref List<KeyValuePair<XYZ, double>> elevationMap)
		{
			List<Curve> rampProjectionEdgeList = this.GetRampProjectionEdgeList(floor1, ref elevationMap);
			if (rampProjectionEdgeList.Count < 1)
			{
				return false;
			}
			List<Curve> rampProjectionEdgeList2 = this.GetRampProjectionEdgeList(floor2, ref elevationMap);
			if (rampProjectionEdgeList2.Count < 1)
			{
				return false;
			}
			foreach (Curve curve in rampProjectionEdgeList)
			{
				XYZ hyendPoint = curve.GetEndPoint(0);
				XYZ hyendPoint2 = curve.GetEndPoint(1);
				foreach (Curve curve2 in rampProjectionEdgeList2)
				{
					XYZ hyendPoint3 = curve2.GetEndPoint(0);
					XYZ hyendPoint4 = curve2.GetEndPoint(1);
					if ((hyendPoint.IsAlmostEqualTo(hyendPoint3, 0.0001) && hyendPoint2.IsAlmostEqualTo(hyendPoint4, 0.0001)) || (hyendPoint.IsAlmostEqualTo(hyendPoint4, 0.0001) && hyendPoint2.IsAlmostEqualTo(hyendPoint3, 0.0001)))
					{
						centerLineList.Add(curve);
						break;
					}
				}
			}
			return true;
		}

		private List<SegmentData> GetSegmentDataByPairFloor(List<Curve> serializeCurves, List<KeyValuePair<XYZ, double>> elevationMap, List<double> floor1WidthList, List<double> floor2WidthList)
		{
			List<SegmentData> list = new List<SegmentData>();
			if (serializeCurves.Count < 1)
			{
				return list;
			}
			Curve curve = serializeCurves[0];
			Curve curve2 = serializeCurves[serializeCurves.Count - 1];
			XYZ startNodePoint = curve.GetEndPoint(0);
			XYZ endNodePoint = curve2.GetEndPoint(1);
			double val = 0.0;
			double val2 = 0.0;
			int num = elevationMap.FindIndex((KeyValuePair<XYZ, double> s1) => this.IsEqualWidth2dPoint(s1.Key, startNodePoint));
			if (num != -1)
			{
				val = AssistFunc.feetToMM(elevationMap[num].Value);
			}
			if (num == -1)
			{
				return list;
			}
			num = elevationMap.FindIndex((KeyValuePair<XYZ, double> s2) => this.IsEqualWidth2dPoint(s2.Key, endNodePoint));
			if (num != -1)
			{
				val2 = AssistFunc.feetToMM(elevationMap[num].Value);
			}
			if (num == -1)
			{
				return list;
			}
			for (int i = 0; i < serializeCurves.Count; i++)
			{
				Curve curve3 = serializeCurves[i];
				XYZ startPoint = curve3.GetEndPoint(0);
				XYZ endPoint = curve3.GetEndPoint(1);
				double dBulge = 0.0;
				if (curve3.GetType() == typeof(Arc))
				{
					Arc arc = curve3 as Arc;
					dBulge = Geometry.GetBulge(startPoint, endPoint, arc.Center, arc.Normal.IsAlmostEqualTo(XYZ.BasisZ));
				}
				num = elevationMap.FindIndex((KeyValuePair<XYZ, double> s1) => this.IsEqualWidth2dPoint(s1.Key, startPoint));
				if (num != -1)
				{
					double dStartElevation = AssistFunc.feetToMM(elevationMap[num].Value);
					num = elevationMap.FindIndex((KeyValuePair<XYZ, double> s2) => this.IsEqualWidth2dPoint(s2.Key, endPoint));
					if (num != -1)
					{
						double dEndElevation = AssistFunc.feetToMM(elevationMap[num].Value);
						double dLeftWidth;
						double dRightWidth;
						if (Geometry.LessThan(val, val2))
						{
							dLeftWidth = floor2WidthList[i];
							dRightWidth = floor1WidthList[i];
						}
						else
						{
							dLeftWidth = floor2WidthList[floor2WidthList.Count - i - 1];
							dRightWidth = floor1WidthList[floor1WidthList.Count - i - 1];
						}
						SegmentData item = new SegmentData(startPoint, endPoint, dBulge, dStartElevation, dEndElevation, dLeftWidth, dRightWidth, 0.0);
						list.Add(item);
					}
				}
			}
			return list;
		}

		private List<Curve> GetRampProjectionEdgeList(Floor floor, ref List<KeyValuePair<XYZ, double>> elevationMap)
		{
			List<Curve> list = new List<Curve>();
			Options options = this.m_Revit.Application.Application.Create.NewGeometryOptions();
			options.ComputeReferences = true;
			options.DetailLevel = (ViewDetailLevel)2;
			foreach (GeometryObject geometryObject in RevitVersionFuncs.GetGeometryObjectArray(floor.get_Geometry(options)))
			{
				Solid solid = geometryObject as Solid;
				if (solid != null)
				{
					foreach (object obj in solid.Faces)
					{
						Face face = (Face)obj;
						if (face.GetType() == typeof(PlanarFace))
						{
							PlanarFace planarFace = face as PlanarFace;
							if (Geometry.IsEqual(planarFace.FaceNormal().Z, 0.0))
							{
								List<Line> projectionLineWithVerticalPlanarFace = this.GetProjectionLineWithVerticalPlanarFace(planarFace, ref elevationMap);
								if (projectionLineWithVerticalPlanarFace != null)
								{
									list.AddRange(projectionLineWithVerticalPlanarFace);
								}
							}
						}
						else if (face.GetType() == typeof(CylindricalFace))
						{
							CylindricalFace verticalface = face as CylindricalFace;
							List<Arc> projectionArcWithVerticalCylindricalFace = this.GetProjectionArcWithVerticalCylindricalFace(verticalface, ref elevationMap);
							if (projectionArcWithVerticalCylindricalFace != null)
							{
								list.AddRange(projectionArcWithVerticalCylindricalFace);
							}
						}
					}
				}
			}
			return list;
		}

		private bool IsEqualWidth2dPoint(XYZ pt1, XYZ pt2)
		{
			XYZ xyz = new XYZ(pt1.X, pt1.Y, 0.0);
			XYZ xyz2 = new XYZ(pt2.X, pt2.Y, 0.0);
			return xyz.IsAlmostEqualTo(xyz2, 1E-09);
		}

		private List<Line> GetProjectionLineWithVerticalPlanarFace(PlanarFace verticalface, ref List<KeyValuePair<XYZ, double>> elevationMap)
		{
            //RampAnalyser.<>c__DisplayClass14_0 <>c__DisplayClass14_ = new RampAnalyser.<>c__DisplayClass14_0();
            //<>c__DisplayClass14_.<>4__this = this;
            //<>c__DisplayClass14_.ptList = new List<XYZ>();
			foreach (object obj in verticalface.EdgeLoops)
			{
				foreach (object obj2 in ((EdgeArray)obj))
				{
					Edge edge = (Edge)obj2;
					Curve curve = edge.AsCurve();
					if (!(curve.GetType() != typeof(Line)))
					{
						Line curve2 = curve as Line;
						XYZ pt = curve2.GetEndPoint(0);
                        //int num = <>c__DisplayClass14_.ptList.FindIndex((XYZ s) => <>c__DisplayClass14_.<>4__this.IsEqualWidth2dPoint(pt, s));
                        //if (num < 0)
                        //{
                        //    <>c__DisplayClass14_.ptList.Add(pt);
                        //}
                        //else if (Geometry.LessThan(<>c__DisplayClass14_.ptList[num].Z, pt.Z))
                        //{
                        //    <>c__DisplayClass14_.ptList[num] = pt;
                        //}
					}
				}
			}
            //if (<>c__DisplayClass14_.ptList.Count < 2)
            //{
            //    return null;
            //}
			List<Line> list = new List<Line>();
			int i = 0;
            //while (i < <>c__DisplayClass14_.ptList.Count - 1)
            //{
            //    XYZ xyz = new XYZ(<>c__DisplayClass14_.ptList[i].X, <>c__DisplayClass14_.ptList[i].Y, 0.0);
            //    XYZ xyz2 = new XYZ(<>c__DisplayClass14_.ptList[i + 1].X, <>c__DisplayClass14_.ptList[i + 1].Y, 0.0);
            //    try
            //    {
            //        Line item = YJKLineEx.YJKGetBound(xyz, xyz2);
            //        list.Add(item);
            //    }
            //    catch (Exception)
            //    {
            //        goto IL_2C4;
            //    }
            //    goto IL_23E;
            //    IL_2C4:
            //    int j = i + 1;
            //    i = j;
            //    continue;
            //    IL_23E:
            //    if (elevationMap.FindIndex((KeyValuePair<XYZ, double> s) => <>c__DisplayClass14_.<>4__this.IsEqualWidth2dPoint(s.Key, <>c__DisplayClass14_.ptList[i])) == -1)
            //    {
            //        elevationMap.Add(new KeyValuePair<XYZ, double>(xyz, <>c__DisplayClass14_.ptList[i].Z));
            //    }
            //    if (elevationMap.FindIndex((KeyValuePair<XYZ, double> s) => <>c__DisplayClass14_.<>4__this.IsEqualWidth2dPoint(s.Key, <>c__DisplayClass14_.ptList[i + 1])) == -1)
            //    {
            //        elevationMap.Add(new KeyValuePair<XYZ, double>(xyz2, <>c__DisplayClass14_.ptList[i + 1].Z));
            //        goto IL_2C4;
            //    }
            //    goto IL_2C4;
            //}
			return list;
		}

		private List<Arc> GetProjectionArcWithVerticalCylindricalFace(CylindricalFace verticalface, ref List<KeyValuePair<XYZ, double>> elevationMap)
		{
            //RampAnalyser.<>c__DisplayClass15_0 <>c__DisplayClass15_ = new RampAnalyser.<>c__DisplayClass15_0();
            //<>c__DisplayClass15_.<>4__this = this;
            //XYZ origin = verticalface.Origin;
            //XYZ axis = verticalface.Axis;
            //XYZ xyz = null;
            //<>c__DisplayClass15_.ptList = new List<XYZ>();
            //foreach (object obj in verticalface.EdgeLoops)
            //{
            //    foreach (object obj2 in ((EdgeArray)obj))
            //    {
            //        Edge edge = (Edge)obj2;
            //        Curve curve = edge.AsCurve();
            //        if (!(curve.GetType() == typeof(Line)))
            //        {
            //            IList<XYZ> list = curve.Tessellate();
            //            XYZ ptS = curve.GetEndPoint(0);
            //            int num = <>c__DisplayClass15_.ptList.FindIndex((XYZ s) => <>c__DisplayClass15_.<>4__this.IsEqualWidth2dPoint(ptS, s));
            //            if (num < 0)
            //            {
            //                <>c__DisplayClass15_.ptList.Add(ptS);
            //                xyz = list[list.Count / 2];
            //            }
            //            else if (Geometry.LessThan(<>c__DisplayClass15_.ptList[num].Z, ptS.Z))
            //            {
            //                <>c__DisplayClass15_.ptList[num] = ptS;
            //                xyz = list[list.Count / 2];
            //            }
            //            XYZ ptE = curve.GetEndPoint(1);
            //            num = <>c__DisplayClass15_.ptList.FindIndex((XYZ s) => <>c__DisplayClass15_.<>4__this.IsEqualWidth2dPoint(ptE, s));
            //            if (num < 0)
            //            {
            //                <>c__DisplayClass15_.ptList.Add(ptE);
            //                xyz = list[list.Count / 2];
            //            }
            //            else if (Geometry.LessThan(<>c__DisplayClass15_.ptList[num].Z, ptE.Z))
            //            {
            //                <>c__DisplayClass15_.ptList[num] = ptE;
            //                xyz = list[list.Count / 2];
            //            }
            //        }
            //    }
            //}
            //if (<>c__DisplayClass15_.ptList.Count < 2)
            //{
            //    return null;
            //}
            List<Arc> list2 = new List<Arc>();
            //int i;
            //int j;
            //for (i = 0; i < <>c__DisplayClass15_.ptList.Count - 1; i = j)
            //{
            //    XYZ xyz2 = new XYZ(<>c__DisplayClass15_.ptList[i].X, <>c__DisplayClass15_.ptList[i].Y, 0.0);
            //    XYZ xyz3 = new XYZ(<>c__DisplayClass15_.ptList[i + 1].X, <>c__DisplayClass15_.ptList[i + 1].Y, 0.0);
            //    xyz = new XYZ(xyz.X, xyz.Y, 0.0);
            //    Arc item = this.m_Revit.Application.Application.CreatYJKArc(xyz2, xyz3, xyz);
            //    list2.Add(item);
            //    if (elevationMap.FindIndex((KeyValuePair<XYZ, double> s) => <>c__DisplayClass15_.<>4__this.IsEqualWidth2dPoint(s.Key, <>c__DisplayClass15_.ptList[i])) == -1)
            //    {
            //        elevationMap.Add(new KeyValuePair<XYZ, double>(xyz2, <>c__DisplayClass15_.ptList[i].Z));
            //    }
            //    if (elevationMap.FindIndex((KeyValuePair<XYZ, double> s) => <>c__DisplayClass15_.<>4__this.IsEqualWidth2dPoint(s.Key, <>c__DisplayClass15_.ptList[i + 1])) == -1)
            //    {
            //        elevationMap.Add(new KeyValuePair<XYZ, double>(xyz3, <>c__DisplayClass15_.ptList[i + 1].Z));
            //    }
            //    j = i + 1;
            //}
			return list2;
		}

		private Curve SerializeCurve(Curve curve, XYZ ptStart)
		{
			XYZ hyendPoint = curve.GetEndPoint(0);
			XYZ hyendPoint2 = curve.GetEndPoint(1);
			if (hyendPoint.IsAlmostEqualTo(ptStart, 0.0001))
			{
				return curve;
			}
			Line line = curve as Line;
			if (null != line)
			{
				return YJKLineEx.YJKGetBound(hyendPoint2, hyendPoint);
			}
			Arc arc = curve as Arc;
			if (null != arc)
			{
				XYZ radianPnt = Geometry.CalculatMidPoint(arc);
				return this.m_Revit.Application.Application.CreatYJKArc(hyendPoint2, hyendPoint, radianPnt);
			}
			return null;
		}

		private XYZ GetOtherPoint(Curve curve, XYZ ptCurrent)
		{
			XYZ hyendPoint = curve.GetEndPoint(0);
			XYZ hyendPoint2 = curve.GetEndPoint(1);
			if (ptCurrent.IsAlmostEqualTo(hyendPoint, 0.0001))
			{
				return hyendPoint2;
			}
			if (ptCurrent.IsAlmostEqualTo(hyendPoint2, 0.0001))
			{
				return hyendPoint;
			}
			return null;
		}

		private XYZ GetNextPoint(XYZ nodeKey, List<Curve> nodeValue, XYZ ptPrior, ref Curve currentCurve)
		{
			if (nodeValue.Count == 1)
			{
				if (ptPrior != null)
				{
					currentCurve = nodeValue[0];
					return null;
				}
				currentCurve = null;
				return this.GetOtherPoint(nodeValue[0], nodeKey);
			}
			else
			{
				XYZ otherPoint = this.GetOtherPoint(nodeValue[0], nodeKey);
				XYZ otherPoint2 = this.GetOtherPoint(nodeValue[1], nodeKey);
				if (ptPrior.IsAlmostEqualTo(otherPoint, 0.0001))
				{
					currentCurve = nodeValue[0];
					return otherPoint2;
				}
				if (ptPrior.IsAlmostEqualTo(otherPoint2, 0.0001))
				{
					currentCurve = nodeValue[1];
					return otherPoint;
				}
				return null;
			}
		}

		private void SetSegmentVertRadius(List<SegmentData> lstSegmentData, List<double> lstVertArcRadius)
		{
			if (lstSegmentData.Count != lstVertArcRadius.Count)
			{
				return;
			}
			for (int i = 0; i < lstSegmentData.Count; i++)
			{
				lstSegmentData[i].VertArcRadius = lstVertArcRadius[i];
			}
		}

		private ExternalCommandData m_Revit;
	}
}
